bitkeeper revision 1.1010.1.7 (40dc2667VP5fW6QI61kdgU_iNS2Pnw)
authormjw@wray-m-3.hpl.hp.com <mjw@wray-m-3.hpl.hp.com>
Fri, 25 Jun 2004 13:19:35 +0000 (13:19 +0000)
committermjw@wray-m-3.hpl.hp.com <mjw@wray-m-3.hpl.hp.com>
Fri, 25 Jun 2004 13:19:35 +0000 (13:19 +0000)
Tidy up console destruction on domain exit.

tools/xenmgr/lib/EventServer.py
tools/xenmgr/lib/XendConsole.py
tools/xenmgr/lib/XendDomain.py
tools/xenmgr/lib/server/SrvConsoleDir.py
tools/xenmgr/lib/server/SrvConsoleServer.py
tools/xenmgr/lib/server/SrvDomainDir.py
tools/xenmgr/lib/server/channel.py
tools/xenmgr/lib/server/console.py
tools/xenmgr/lib/server/controller.py

index 6fae2b9ccfdee7c6e901a4ecdce0a26f3ca2c605..20c567ada7cd0ae96294a64aec1f005eabfad625 100644 (file)
@@ -4,6 +4,8 @@
 """
 import string
 
+from twisted.internet import reactor
+
 # subscribe a.b.c h: map a.b.c -> h
 # subscribe a.b.* h: map a.b.* -> h
 # subscribe a.b.? h: map a.b.? -> h
@@ -73,7 +75,7 @@ class EventServer:
         """
         if event == None:
             self.handlers.clear()
-        else:
+        elif event in self.handlers:
             del self.handlers[event]
         
     def unsubscribe(self, event, handler):
@@ -88,21 +90,29 @@ class EventServer:
         if handler in hl:
             hl.remove(handler)
 
-    def inject(self, event, val):
-        """Inject an event. Handlers for it are called if runing, otherwise
+    def inject(self, event, val, async=1):
+        """Inject an event. Handlers for it are called if running, otherwise
         it is queued.
 
         event  event type
         val    event value
         """
         if self.run:
-            #print ">event", event, val
-            self.call_event_handlers(event, event, val)
-            self.call_query_handlers(event, val)
-            self.call_star_handlers(event, val)
+            if async:
+                reactor.callLater(0, self.call_handlers, event, val)
+            else:
+                self.notify_handlers(event, val)
         else:
             self.queue.append( (event, val) )
 
+    def call_handlers(self, event, val):
+        """Internal method to call event handlers.
+        """
+        #print ">event", event, val
+        self.call_event_handlers(event, event, val)
+        self.call_query_handlers(event, val)
+        self.call_star_handlers(event, val)
+
     def call_event_handlers(self, key, event, val):
         """Call the handlers for an event.
         It is safe for handlers to subscribe or unsubscribe.
index 19ad7eeae35db070aa50d58438fb3598c788c19c..dcf992d376e9c8f228c861adb2d31280370cba73 100644 (file)
@@ -21,10 +21,10 @@ class XendConsoleInfo:
 
     def __init__(self, console, dom1, port1, dom2, port2, conn=None):
         self.console = console
-        self.dom1  = dom1
-        self.port1 = port1
-        self.dom2  = dom2
-        self.port2 = port2
+        self.dom1  = int(dom1)
+        self.port1 = int(port1)
+        self.dom2  = int(dom2)
+        self.port2 = int(port2)
         self.conn  = conn
         #self.id = "%d.%d-%d.%d" % (self.dom1, self.port1, self.dom2, self.port2)
         self.id = str(port1)
@@ -81,6 +81,7 @@ class XendConsole:
             print 'XendConsole> rebooted: removing all console info'
             self.rm_all()
         eserver.subscribe('xend.domain.died', self.onDomainDied)
+        eserver.subscribe('xend.domain.destroy', self.onDomainDied)
 
     def rm_all(self):
         """Remove all console info. Used after reboot.
@@ -104,11 +105,15 @@ class XendConsole:
                 self._delete_console(c.id)
 
     def onDomainDied(self, event, val):
-        print 'onDomainDied', "dom=", dom,
         dom = int(val)
+        #print 'XendConsole>onDomainDied', 'event', event, "dom=", dom
         for c in self.consoles():
-            print 'onDomainDied', "dom=", dom, "dom1=", c.dom1, "dom2=", c.dom2
+            #print 'onDomainDied', "dom=", dom, "dom1=", c.dom1, "dom2=", c.dom2
             if (c.dom1 == dom) or (c.dom2 == dom):
+                'XendConsole>onDomainDied', 'delete console dom=', dom
+                ctrl = xcd.get_domain_console(dom)
+                if ctrl:
+                    ctrl.close()
                 self._delete_console(c.id)
 
     def sync(self):
index 5c31079b2e547f485ba691a3637d72ab61bd4bd2..2eaa9b624187076d3f8b467ceabf839079e96b38 100644 (file)
@@ -79,11 +79,10 @@ class XendDomain:
                 self._delete_domain(domid)
         deferred = defer.DeferredList(dlist, fireOnOneErrback=1)
         def cbok(val):
-            print "doms:"
-            for d in self.domain.values(): print 'dom', d
-            print "refresh..."
+            #print "doms:"
+            #for d in self.domain.values(): print 'dom', d
             self.refresh()
-            print "doms:"
+            print "XendDomain>initial_refresh> doms:"
             for d in self.domain.values(): print 'dom', d
         deferred.addCallback(cbok)
 
@@ -148,11 +147,14 @@ class XendDomain:
             self.db.delete(id)
 
     def reap(self):
-        print 'reap>'
+        """Go through the domains looking for ones that have crashed or stopped.
+        Tidy them up.
+        """
+        print 'XendDomain>reap>'
         domlist = xc.domain_getinfo()
         casualties = []
         for d in domlist:
-            print 'dom', d
+            #print 'dom', d
             dead = 0
             dead = dead or (d['crashed'] or d['shutdown'])
             dead = dead or (d['dying'] and
@@ -161,12 +163,12 @@ class XendDomain:
                 casualties.append(d)
         for d in casualties:
             id = str(d['dom'])
-            print 'died> id=', id, d
+            print 'XendDomain>reap> died id=', id, d
             dominfo = self.domain.get(id)
             if not dominfo: continue
             dominfo.died()
             self.domain_destroy(id, refresh=0)
-        print 'reap<'
+        print 'XendDomain>reap<'
 
     def refresh(self):
         """Refresh domain list from Xen.
@@ -203,6 +205,8 @@ class XendDomain:
             try:
                 self._delete_domain(id)
             except:
+                print 'refresh_domain: error'
+                raise
                 pass
         else:
             d = self.domain.get(id)
index 89b092c18d73f1feddfb7d1361195f2ae00b5f79..e5c0308f80654ad8d2604041962362b026327d5d 100644 (file)
@@ -18,7 +18,8 @@ class SrvConsoleDir(SrvDir):
         try:
             info = self.xconsole.console_get(x)
             val = SrvConsole(info)
-        except KeyError:
+        except KeyError, ex:
+            print 'SrvConsoleDir>', ex
             pass
         return val
 
index f3316fef1c8141f90446323449e3126cb34d41dc..d6bb976b3c0d2ac7b310c22f8e5a725ed42040a3 100644 (file)
@@ -378,7 +378,10 @@ class EventProtocol(protocol.Protocol):
         return ['ok']
 
     def op_info(self, name, req):
-        val = self.daemon.consoles()
+        val = ['info']
+        val += self.daemon.consoles()
+        val += self.daemon.blkifs()
+        val += self.daemon.netifs()
         return val
 
     def op_sys_subscribe(self, name, v):
@@ -603,6 +606,9 @@ class Daemon:
         d = self.blkifCF.createInstance(dom, recreate=recreate)
         return d
 
+    def blkifs(self):
+        return [ x.sxpr() for x in self.blkifCF.getInstances() ]
+
     def blkif_get(self, dom):
         return self.blkifCF.getInstanceByDom(dom)
 
@@ -637,6 +643,9 @@ class Daemon:
         """
         return self.netifCF.createInstance(dom, recreate=recreate)
 
+    def netifs(self):
+        return [ x.sxpr() for x in self.netifCF.getInstances() ]
+
     def netif_get(self, dom):
         return self.netifCF.getInstanceByDom(dom)
 
@@ -677,8 +686,7 @@ class Daemon:
         console = self.get_console(id)
         if not console:
             raise ValueError('Invalid console id')
-        if console.conn:
-            console.conn.loseConnection()
+        console.disconnect()
 
     def domain_shutdown(self, dom, reason):
         """Shutdown a domain.
index 7bb2996d9bebd7d8ac67c18b02ed8a5f3ce59027..67a6a9bc7fda0e4e7b840bc8fd1941fe1affe976 100644 (file)
@@ -24,7 +24,8 @@ class SrvDomainDir(SrvDir):
         try:
             dom = self.xd.domain_get(x)
             val = SrvDomain(dom)
-        except KeyError:
+        except KeyError, ex:
+            print 'SrvDomainDir>', ex
             pass
         return val
 
@@ -46,7 +47,7 @@ class SrvDomainDir(SrvDir):
             config = pin.get_val()
             ok = 1
         except Exception, ex:
-            print ex
+            print 'op_create>', ex
         if not ok:
             req.setResponseCode(http.BAD_REQUEST, "Invalid configuration")
             return "Invalid configuration"
index 3f2a7a63825f71cda69c5e0ee7d7f38971ed2476..cf890918e528af648f7fda7878bc83fab689a224 100755 (executable)
@@ -49,6 +49,7 @@ class ChannelFactory:
         """Get the channel for the given domain.
         Construct if necessary.
         """
+        dom = int(dom)
         for chan in self.channels.values():
             if not isinstance(chan, Channel): continue
             if chan.dom == dom:
@@ -199,7 +200,7 @@ class Channel(BaseChannel):
         """
         BaseChannel.__init__(self, factory)
         # Domain.
-        self.dom = dom
+        self.dom = int(dom)
         # Domain port (object).
         self.port = self.factory.createPort(dom)
         # Channel port (int).
@@ -210,6 +211,7 @@ class Channel(BaseChannel):
         self.devs_by_type = {}
         # Output queue.
         self.queue = []
+        self.closed = 0
 
     def getLocalPort(self):
         """Get the local port.
@@ -225,11 +227,12 @@ class Channel(BaseChannel):
         """Close the channel. Calls lostChannel() on all its devices and
         channelClosed() on the factory.
         """
+        self.closed = 1
         for d in self.devs:
             d.lostChannel()
         self.factory.channelClosed(self)
-        del self.devs
-        del self.devs_by_type
+        self.devs = []
+        self.devs_by_type = {}
 
     def registerDevice(self, types, dev):
         """Register a device controller.
@@ -237,20 +240,21 @@ class Channel(BaseChannel):
         @param types message types the controller handles
         @param dev   device controller
         """
+        if self.closed: return
         self.devs.append(dev)
         for ty in types:
             self.devs_by_type[ty] = dev
 
-    def unregisterDevice(self, dev):
+    def deregisterDevice(self, dev):
         """Remove the registration for a device controller.
 
         @param dev device controller
         """
-        self.devs.remove(dev)
-        types = [ ty for (ty, d) in self.devs_by_type.items()
-                  if d == dev ]
+        if dev in self.devs:
+            self.devs.remove(dev)
+        types = [ ty for (ty, d) in self.devs_by_type.items() if d == dev ]
         for ty in types:
-            del devs_by_type[ty]
+            del self.devs_by_type[ty]
 
     def getDevice(self, type):
         """Get the device controller handling a message type.
index 6db905dc0b1de6a99d2da5743e46bbb32355fc29..f26a4dd3c6d51fe901058ba25788c763e1f150be 100755 (executable)
@@ -103,7 +103,7 @@ class ConsoleController(controller.Controller):
     """
 
     def __init__(self, factory, dom, console_port):
-        #print 'ConsoleController> dom=', dom
+        #print 'ConsoleController> dom=', dom, type(dom)
         controller.Controller.__init__(self, factory, dom)
         self.majorTypes = [ CMSG_CONSOLE ]
         self.status = "new"
@@ -120,6 +120,7 @@ class ConsoleController(controller.Controller):
 
     def sxpr(self):
         val =['console',
+              ['status',       self.status ],
               ['id',           self.idx ],
               ['domain',       self.dom ],
               ['local_port',   self.channel.getLocalPort() ],
@@ -139,10 +140,17 @@ class ConsoleController(controller.Controller):
         return self.status == 'connected'
 
     def close(self):
-        self.status = "closed"
-        self.listener.stopListening()
-        self.deregisterChannel()
-        self.lostChannel()
+        try:
+            #print 'ConsoleController> close dom=', self.dom
+            self.status = "closed"
+            if self.conn:
+                self.conn.loseConnection()
+            self.listener.stopListening()
+            self.deregisterChannel()
+            self.lostChannel()
+        except Exception, ex:
+            print 'ConsoleController>close>', ex
+            raise
 
     def listen(self):
         """Listen for TCP connections to the console port..
@@ -166,6 +174,8 @@ class ConsoleController(controller.Controller):
         return 0
 
     def disconnect(self):
+        if self.conn:
+            self.conn.loseConnection()
         self.addr = None
         self.conn = None
         self.listen()
index 08afdfd634b6b870a0de2e4dc0e72709fda032ce..900c2d55b008332984504e1d3a1bbb9a8c0bc304 100755 (executable)
@@ -36,14 +36,14 @@ class CtrlMsgRcvr:
         pass
     
     def registerChannel(self):
-        print 'CtrlMsgRcvr>registerChannel>', self
+        #print 'CtrlMsgRcvr>registerChannel>', self
         self.channel = self.channelFactory.domChannel(self.dom)
         self.idx = self.channel.getIndex()
         if self.majorTypes:
             self.channel.registerDevice(self.majorTypes, self)
         
     def deregisterChannel(self):
-        print 'CtrlMsgRcvr>deregisterChannel>', self
+        #print 'CtrlMsgRcvr>deregisterChannel>', self
         if self.channel:
             self.channel.deregisterDevice(self)
             del self.channel
@@ -92,13 +92,16 @@ class ControllerFactory(CtrlMsgRcvr):
         return None
 
     def delInstance(self, instance):
+        #print 'ControllerFactory>delInstance>', instance.idx
         if instance.idx in self.instances:
+            #print 'ControllerFactory>delInstance> remove', instance.idx
             del self.instances[instance.idx]
 
     def createInstance(self, dom, recreate=0):
         raise NotImplementedError()
 
     def instanceClosed(self, instance):
+        #print 'ControllerFactory>instanceClosed>', instance.idx, instance
         self.delInstance(instance)
 
     def addDeferred(self):
@@ -126,7 +129,7 @@ class Controller(CtrlMsgRcvr):
     def __init__(self, factory, dom):
         CtrlMsgRcvr.__init__(self)
         self.factory = factory
-        self.dom = dom
+        self.dom = int(dom)
         self.channel = None
         self.idx = None
 
@@ -135,6 +138,7 @@ class Controller(CtrlMsgRcvr):
         self.lostChannel()
 
     def lostChannel(self):
+        #print 'Controller>lostChannel>', self, self.factory
         self.factory.instanceClosed(self)
 
 class Dev: